package com.smsc.headend.task.engine.executor.impl.scheduleread;

import cn.hutool.core.convert.Convert;
import cn.hutool.json.JSONUtil;
import com.smsc.headend.common.enums.errorcode.TaskExecuteErrorCode;
import com.smsc.headend.common.utils.RedisUtils;
import com.smsc.headend.module.asset.dmo.ComConfigDMO;
import com.smsc.headend.module.asset.dmo.MeterConfigDMO;
import com.smsc.headend.module.asset.entity.ComEntity;
import com.smsc.headend.module.asset.entity.Meter;
import com.smsc.headend.module.data.dmo.DeviceSAPandKeys;
import com.smsc.headend.module.data.dto.DataItemDTO;
import com.smsc.headend.module.protocol.cosem.util.ByteUtils;
import com.smsc.headend.module.task.dto.AtomicTask;
import com.smsc.headend.module.task.dto.Task;
import com.smsc.headend.module.task.enums.DeviceActionType;
import com.smsc.headend.task.engine.exception.UDISTaskExecutorException;
import com.smsc.headend.task.engine.executor.TaskExecutor;
import com.smsc.headend.task.engine.facade.DataItemFacade;
import com.smsc.headend.task.engine.handler.impl.collection.ReadScheduleReadBufferHandler;
import com.smsc.headend.module.task.dto.AtomicTaskState;
import com.smsc.headend.task.engine.service.ConnectorService;
import com.smsc.headend.task.engine.service.FeignAssetManagementService;
import com.smsc.headend.task.engine.service.asset.AssetService;
import com.smsc.headend.task.engine.service.task.TaskPacketService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;

@Slf4j
@Component
public class ScheduleReadExecutor implements TaskExecutor {
    @Autowired
    TaskPacketService packetService;
    @Autowired
    ConnectorService connectorService;
    @Autowired
    RedisUtils redisUtils;
    @Autowired
    FeignAssetManagementService assetManagementRemoteService;
    @Autowired
    DataItemFacade dataItemFacade;
    @Autowired
    AssetService assetService;

    @Override
    public AtomicTaskState execute(Task task, AtomicTask atomicTask) throws UDISTaskExecutorException {
        log.info("ScheduleReadExecutor start ,task is {}, atomicTask is {}", JSONUtil.toJsonStr(task), JSONUtil.toJsonStr(atomicTask));
        Meter meter = getMeter(task, assetService);
        MeterConfigDMO meterConfigDMO = task.getMeterId() == null ? null : assetService.getMeterConfigById(task.getMeterId());

        ComEntity terminal = assetService.getComById(task.getComId());
        ComConfigDMO comConfigDMO = assetService.getComConfigById(task.getComId());

        Boolean readTerminalFlag = isReadFromTerminal(task);
//        List<DataItemDTO> dataItemCosemList = dataItemFacade.getDataItemsByOperation(meter, terminal, dictionary, getParameterMap(task, atomicTask), comConfigDMO.getModelId());

        List<DataItemDTO> dataItemCosemList = getDCUReadCollectionData(meter, getParameterMap(task, atomicTask), comConfigDMO);
        log.info("dataItemCosemList :{}", JSONUtil.toJsonStr(dataItemCosemList));

        if (CollectionUtils.isEmpty(dataItemCosemList)) {
            throw new UDISTaskExecutorException(TaskExecuteErrorCode.DATAITEM_NOT_EXISTS.toString());
        }

        DataItemDTO dataItemDto = dataItemCosemList.get(0);
        DeviceSAPandKeys deviceKeys = meter != null ?
                assetManagementRemoteService.getMeterCommunicationKey(meter.getMeterId(), dataItemDto.getRoleId()) : assetManagementRemoteService.getTerminalCommunicationKey(terminal.getComId(), dataItemDto.getRoleId());
        byte[] packets = packetService.buildReadOneAttributePacket(dataItemCosemList.get(0), readTerminalFlag ? comConfigDMO : meterConfigDMO, deviceKeys);
        if (packets == null) {
            log.error("build packet fail {}", dataItemCosemList.get(0));
            throw new UDISTaskExecutorException(TaskExecuteErrorCode.BUILD_REQUEST_FAIL.toString());
        }

        log.debug(ByteUtils.byteToHexString(packets));
        connectorService.sendPacket(task, atomicTask, dataItemDto.getRoleId(), task.getIsODR(), packets);
        return createAtomicState(ReadScheduleReadBufferHandler.class);
    }


    private Boolean isReadFromTerminal(Task task) {
        if (task.getMeterId() == null) {
            return true;
        }
        return false;
    }

    private List<DataItemDTO> getDCUReadCollectionData(Meter meter, Map<String, Object> paramMap, ComConfigDMO comConfigDMO) {
        if (null == meter) {
            return dataItemFacade.getDataItemsById(comConfigDMO.getModelId(), DeviceActionType.Get, Convert.toLong(paramMap.get("dataItemId")));
        }
        return dataItemFacade.getDataItemsById(meter.getModelId(), DeviceActionType.Get, Convert.toLong(paramMap.get(
                "dataItemId")));
    }
}
